package com.tian.intercptor;

import com.tian.annotation.MethodInvokeLogAnnotation;
import com.tian.util.UserCacheUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author tianwc  公众号：java后端技术全栈、面试专栏
 * @version 1.0.0
 * @date 2022年11月01日 17:24
 * <p>
 * 日志切面
 */
@Aspect
@Component
@Slf4j
public class MethodInvokeLogAspect {

    /**
     * 这里我们使用注解的形式
     * 当然，我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method
     * 切点表达式:   execution(...)
     */
    @Pointcut("@annotation(com.tian.annotation.MethodInvokeLogAnnotation)")
    public void methodInvokeLog() {

    }

    /**
     * 接口请求参数、相应参数、耗时、路径等信息打印
     */
    @Around("methodInvokeLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {

        long startTime = System.currentTimeMillis();

        Object result;

        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            log.error("An error occurred during method execution: " + e.getMessage(), e);
            throw e;
        }
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        MethodInvokeLogAnnotation argsLogAnnotation = method.getAnnotation(MethodInvokeLogAnnotation.class);

        String methodDescription = argsLogAnnotation.methodDescription();
        long endTime = System.currentTimeMillis();
        String className = joinPoint.getTarget().getClass().getName();

        log.info("日志内容: class name is{} - method name is {} - method desc  {} 耗时: {}ms, 调用时间: {}", method.getName(), className, methodDescription, (endTime - startTime), endTime);

        UserCacheUtil.clearUser();

        return result;
    }
}
